// ============ AI工具调度系统 - 内置文件系统工具 ============

import type { ToolDefinition } from '../types';
import { invoke } from '@tauri-apps/api/core';
import { useWorkspaceStore } from '../../workspace';
import { addLocalHistorySnapshot } from '../../../assets/local-history';
import { useAiTimelineStore } from '../../aiTimeline';
import { normalizePath, classifyError } from '../utils';

/**
 * 内置文件写入工具
 */
export const BUILTIN_WRITE_FILE: ToolDefinition = {
  id: 'write_file',
  name: 'Write File',
  description: 'Create a new file or overwrite an existing file with provided content',
  parameters: {
    type: 'object',
    required: ['path', 'content'],
    properties: {
      path: { type: 'string' },
      content: { type: 'string' }
    }
  },
  metadata: { category: 'workspace', tags: ['fs', 'write'] },
  handler: async (params) => {
    const { path, content } = params || {};
    if (!path || typeof path !== 'string') throw new Error('Parameter "path" is required');
    
    const ws = useWorkspaceStore();
    const absPath = normalizePath(path, ws.workspaceRoot);

    let existed = true;
    try { await invoke('fs_stat', { path: absPath }); } catch { existed = false; }

    // 如果目标已存在，则先保存"修改前"的本地历史快照
    let beforeContent = '';
    if (existed) {
      try {
        const prev = await invoke<string>('fs_read_text', { path: absPath });
        beforeContent = String(prev ?? '');
        await addLocalHistorySnapshot(absPath, beforeContent);
      } catch {}
    }

    const afterContent = String(content ?? '');
    await invoke('fs_write_text', { path: absPath, content: afterContent, createDirs: true });
    
    try {
      const ai = useAiTimelineStore();
      await ai.addEntry({ 
        kind: existed ? 'modify' : 'create', 
        path: absPath, 
        tool: 'write_file',
        beforeContent: existed ? beforeContent : undefined,
        afterContent: afterContent,
        fileSize: afterContent.length
      });
    } catch {}
    
    try { ws.applyFileChange(existed ? 'modify' : 'create', absPath); } catch {}
    return { path: absPath, created: !existed, size: afterContent.length };
  }
};

/**
 * 内置目录创建工具
 */
export const BUILTIN_CREATE_DIRECTORY: ToolDefinition = {
  id: 'create_directory',
  name: 'Create Directory',
  description: 'Create a new directory (recursively) or succeed silently if it already exists',
  parameters: {
    type: 'object',
    required: ['path'],
    properties: { path: { type: 'string' } }
  },
  metadata: { category: 'workspace', tags: ['fs', 'mkdir'] },
  handler: async (params) => {
    const { path } = params || {};
    if (!path || typeof path !== 'string') throw new Error('Parameter "path" is required');
    
    const ws = useWorkspaceStore();
    const absPath = normalizePath(path, ws.workspaceRoot);

    await invoke('fs_mkdir', { path: absPath, recursive: true });
    
    try {
      const ai = useAiTimelineStore();
      await ai.addEntry({ 
        kind: 'create', 
        path: absPath, 
        tool: 'create_directory',
        beforeContent: undefined,
        afterContent: undefined
      });
    } catch {}
    
    try { ws.applyFileChange('create', absPath); } catch {}
    return { path: absPath };
  }
};

/**
 * 内置目录列表工具
 */
export const BUILTIN_LIST_DIRECTORY: ToolDefinition = {
  id: 'list_directory',
  name: 'List Directory',
  description: 'List directory entries with [FILE] or [DIR] prefixes',
  parameters: {
    type: 'object',
    required: ['path'],
    properties: { path: { type: 'string' } }
  },
  metadata: { category: 'workspace', tags: ['fs', 'ls'] },
  handler: async (params) => {
    const { path } = params || {};
    if (!path || typeof path !== 'string') throw new Error('Parameter "path" is required');
    
    const ws = useWorkspaceStore();
    const absPath = normalizePath(path, ws.workspaceRoot);

    const entries = await invoke<any[]>('fs_read_dir', { path: absPath });
    const lines = (Array.isArray(entries) ? entries : []).map(e => `${e.is_dir ? '[DIR]' : '[FILE]'} ${e.name}`);
    // 注意：list_directory 不记录 AI 时间线，因为它是只读操作
    return { path: absPath, entries: lines };
  }
};

/**
 * 内置文件移动/重命名工具
 */
export const BUILTIN_MOVE_FILE: ToolDefinition = {
  id: 'move_file',
  name: 'Move/Rename File or Directory',
  description: 'Move or rename a file/directory; fail if destination exists',
  parameters: {
    type: 'object',
    required: ['source', 'destination'],
    properties: {
      source: { type: 'string' },
      destination: { type: 'string' }
    }
  },
  metadata: { category: 'workspace', tags: ['fs', 'move', 'rename'] },
  handler: async (params) => {
    const { source, destination } = params || {};
    if (!source || !destination) throw new Error('Parameters "source" and "destination" are required');
    
    const ws = useWorkspaceStore();
    const absSource = normalizePath(source, ws.workspaceRoot);
    const absDest = normalizePath(destination, ws.workspaceRoot);

    // 目标存在则失败
    let destExists = false;
    try { await invoke('fs_stat', { path: absDest }); destExists = true; } catch { destExists = false; }
    if (destExists) throw new Error('Destination already exists');

    // 检查源文件是否为目录
    let isSourceDirectory = false;
    try {
      const sourceStat = await invoke('fs_stat', { path: absSource }) as any;
      isSourceDirectory = sourceStat.isDirectory || false;
    } catch {}

    await invoke('fs_rename', { from: absSource, to: absDest });

    try {
      const ai = useAiTimelineStore();
      await ai.addEntry({
        kind: 'move',
        path: absDest, // 记录目标路径作为主路径
        tool: 'move_file',
        note: `Moved from ${absSource} to ${absDest}`,
        beforeContent: undefined,
        afterContent: undefined,
        operationMeta: {
          sourcePath: absSource,
          targetPath: absDest,
          isDirectory: isSourceDirectory,
          beforeExists: true, // 源文件必须存在
          afterExists: true   // 移动后目标位置存在
        }
      });
    } catch {}
    
    try { ws.applyFileChange('rename', absDest, absSource); } catch {}
    return { from: absSource, to: absDest };
  }
};

/**
 * 内置文件搜索工具
 */
export const BUILTIN_SEARCH_FILES: ToolDefinition = {
  id: 'search_files',
  name: 'Search Files/Directories',
  description: 'Recursively search for files/directories by pattern (case-insensitive) with glob exclude',
  parameters: {
    type: 'object',
    required: ['path', 'pattern'],
    properties: {
      path: { type: 'string' },
      pattern: { type: 'string' },
      excludePatterns: { type: 'array', items: { type: 'string' } }
    }
  },
  metadata: { category: 'workspace', tags: ['fs', 'search'] },
  handler: async (params, context) => {
    const { path, pattern, excludePatterns } = params || {};
    if (!path || !pattern) throw new Error('Parameters "path" and "pattern" are required');
    
    const ws = useWorkspaceStore();
    const absRoot = normalizePath(path, ws.workspaceRoot);

    const toReg = (g: string) => {
      // very simple glob -> regex
      const esc = String(g).replace(/[.+^${}()|\[\]\\]/g, '\\$&').replace(/\\\*\\\*/g, '::DOUBLE_STAR::');
      const withStar = esc.replace(/\\\*/g, '[^/]*').replace(/\\\?/g, '.');
      const dbl = withStar.replace(/::DOUBLE_STAR::/g, '.*');
      return new RegExp('^' + dbl + '$', 'i');
    };

    const excludes = Array.isArray(excludePatterns) ? excludePatterns.map(toReg) : [];
    const pat = toReg('*' + String(pattern) + '*');

    const normPathForMatch = (p: string) => String(p || '').replace(/[\\]/g, '/');

    const results = [] as string[];
    const queue: string[] = [absRoot];
    const signal = context?.signal;

    while (queue.length) {
      if (signal?.aborted) throw new DOMException('Aborted', 'AbortError');
      const dir = queue.shift()!;
      let entries: any[] = [];
      try { entries = await invoke<any[]>('fs_read_dir', { path: dir }); } catch { entries = []; }
      for (const e of entries) {
        const p = e.path || '';
        const isDir = !!e.is_dir;
        const pathNormalized = normPathForMatch(p);
        const excluded = excludes.some(rx => rx.test(pathNormalized));
        if (excluded) continue;
        const nameNormalized = normPathForMatch(e.name || '');
        if (pat.test(nameNormalized) || pat.test(pathNormalized)) {
          results.push(p);
        }
        if (isDir) queue.push(p);
        if (results.length >= 10000) break; // 防止结果过多
      }
      if (results.length >= 10000) break;
    }

    // 注意：search_files 不记录 AI 时间线，因为它是只读操作
    return { root: absRoot, matches: results };
  }
};

/**
 * 内置文件信息获取工具
 */
export const BUILTIN_GET_FILE_INFO: ToolDefinition = {
  id: 'get_file_info',
  name: 'Get File/Directory Info',
  description: 'Get file/directory metadata (size, times, type). Some fields may be unavailable on this platform.',
  parameters: { 
    type: 'object', 
    required: ['path'], 
    properties: { path: { type: 'string' } } 
  },
  metadata: { category: 'workspace', tags: ['fs', 'stat'] },
  handler: async (params) => {
    const { path } = params || {};
    if (!path || typeof path !== 'string') throw new Error('Parameter "path" is required');
    
    const ws = useWorkspaceStore();
    const absPath = normalizePath(path, ws.workspaceRoot);

    const st: any = await invoke('fs_stat', { path: absPath });
    // 注意：get_file_info 不记录 AI 时间线，因为它是只读操作
    return {
      path: st.path || absPath,
      size: st.size ?? null,
      createdTime: null,
      modifiedTime: st.modified_ms ? new Date(st.modified_ms).toISOString() : null,
      accessTime: null,
      type: st.is_dir ? 'directory' : 'file',
      permissions: null
    };
  }
};

/**
 * 内置单文件读取工具
 */
export const BUILTIN_READ_FILE: ToolDefinition = {
  id: 'read_file',
  name: 'Read File',
  description: '读取文件的全部内容（UTF-8编码）',
  parameters: {
    type: 'object',
    required: ['path'],
    properties: {
      path: { type: 'string', description: '要读取的文件路径' }
    }
  },
  metadata: { 
    timeout: 15000, // 15秒超时（读取大文件可能耗时）
    category: 'workspace', 
    tags: ['fs', 'read', 'file'] 
  },
  handler: async (params, context) => {
    const { path } = params || {};
    if (!path || typeof path !== 'string') {
      throw new Error('Parameter "path" is required and must be a string');
    }

    // 📝 路径规范化
    const ws = useWorkspaceStore();
    const absPath = normalizePath(path, ws.workspaceRoot);

    try {
      // 📁 检查中断信号
      if (context?.signal?.aborted) {
        throw new DOMException('Read operation was aborted', 'AbortError');
      }

      // 📄 使用 Tauri 命令读取文件内容
      const content = await invoke<string>('fs_read_text', { path: absPath });
      
      // 📊 获取文件信息用于返回
      let fileSize = 0;
      let modifiedTime = null;
      try {
        const stat: any = await invoke('fs_stat', { path: absPath });
        fileSize = stat.size || 0;
        modifiedTime = stat.modified_ms ? new Date(stat.modified_ms).toISOString() : null;
      } catch {
        // 如果获取文件信息失败，不影响主要功能
        fileSize = content.length;
      }

      // 注意：read_file 不记录 AI 时间线，因为它是只读操作
      return {
        path: absPath,
        content: content,
        size: fileSize,
        encoding: 'UTF-8',
        modifiedTime: modifiedTime,
        success: true
      };
      
    } catch (error: any) {
      // 😞 错误处理：提供详细的错误信息
      const errorInfo = classifyError(error);
      throw new Error(`Failed to read file: ${errorInfo.message} (${errorInfo.type})`);
    }
  }
};

/**
 * 内置多文件批量读取工具
 */
export const BUILTIN_READ_MULTIPLE_FILES: ToolDefinition = {
  id: 'read_multiple_files',
  name: 'Read Multiple Files',
  description: '同时读取多个文件，失败的读取不会停止整个操作',
  parameters: {
    type: 'object',
    required: ['paths'],
    properties: {
      paths: { 
        type: 'array', 
        items: { type: 'string' },
        description: '要读取的文件路径数组',
        maxItems: 50 // 限制最大文件数量防止滥用
      },
      continueOnError: {
        type: 'boolean',
        description: '是否在遇到错误时继续处理其他文件',
        default: true
      }
    }
  },
  metadata: { 
    timeout: 45000, // 45秒超时（多个文件可能需要更长时间）
    category: 'workspace', 
    tags: ['fs', 'read', 'batch', 'multiple'] 
  },
  handler: async (params, context) => {
    const { paths, continueOnError = true } = params || {};
    
    // ✅ 参数验证
    if (!Array.isArray(paths) || paths.length === 0) {
      throw new Error('Parameter "paths" is required and must be a non-empty array');
    }
    
    if (paths.length > 50) {
      throw new Error('Maximum 50 files can be read in a single operation');
    }
    
    // 检查路径是否都是字符串
    const invalidPaths = paths.filter(p => typeof p !== 'string' || !p.trim());
    if (invalidPaths.length > 0) {
      throw new Error('All paths must be non-empty strings');
    }

    // 📝 路径规范化
    const ws = useWorkspaceStore();
    const normalizedPaths = paths.map(path => normalizePath(path, ws.workspaceRoot));
    
    // 📦 并发读取文件
    const results = [];
    const errors: any[] = [];
    let successCount = 0;
    let failureCount = 0;
    
    // 使用并发模式提高性能，但限制并发数防止资源耗尽
    const CONCURRENT_LIMIT = 5;
    
    for (let i = 0; i < normalizedPaths.length; i += CONCURRENT_LIMIT) {
      // 检查中断信号
      if (context?.signal?.aborted) {
        throw new DOMException('Batch read operation was aborted', 'AbortError');
      }
      
      const batch = normalizedPaths.slice(i, i + CONCURRENT_LIMIT);
      const promises = batch.map(async (absPath, index) => {
        const originalIndex = i + index;
        const originalPath = paths[originalIndex];
        
        try {
          // 读取文件内容
          const content = await invoke<string>('fs_read_text', { path: absPath });
          
          // 获取文件信息
          let fileSize = content.length;
          let modifiedTime = null;
          try {
            const stat: any = await invoke('fs_stat', { path: absPath });
            fileSize = stat.size || content.length;
            modifiedTime = stat.modified_ms ? new Date(stat.modified_ms).toISOString() : null;
          } catch {
            // 忽略统计信息获取失败
          }
          
          successCount++;
          return {
            index: originalIndex,
            path: absPath,
            originalPath: originalPath,
            content: content,
            size: fileSize,
            modifiedTime: modifiedTime,
            success: true,
            error: null
          };
          
        } catch (error: any) {
          failureCount++;
          const errorInfo = classifyError(error);
          
          const errorResult = {
            index: originalIndex,
            path: absPath,
            originalPath: originalPath,
            content: null,
            size: 0,
            modifiedTime: null,
            success: false,
            error: errorInfo
          };
          
          errors.push(errorResult);
          
          if (!continueOnError) {
            throw new Error(`Failed to read file at index ${originalIndex} (${originalPath}): ${errorInfo.message}`);
          }
          
          return errorResult;
        }
      });
      
      // 等待当前批次完成
      const batchResults = await Promise.all(promises);
      results.push(...batchResults);
    }
    
    // 按原始顺序排序结果
    results.sort((a, b) => a.index - b.index);
    
    // 注意：read_multiple_files 不记录 AI 时间线，因为它是只读操作
    return {
      totalFiles: paths.length,
      successCount: successCount,
      failureCount: failureCount,
      continueOnError: continueOnError,
      results: results,
      errors: errors.length > 0 ? errors : undefined,
      summary: `Successfully read ${successCount}/${paths.length} files${failureCount > 0 ? ` (${failureCount} failed)` : ''}`
    };
  }
};